﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
using System;
using System.Text;

public class BuildHelper  
{
    /*
     * strFullPath   --  absulote path
     * strAssetsPath --  path start with Assets
     * 
     */

    public static bool SplitAlpha = false;

    public static string strUIDirRoot = "Assets/UI";
    public static string strResRoot = "Assets/PackRes";
    public static string strLuaFilesRoot = "Assets/LuaScripts";

    public static void InitDicFolders(ref Dictionary<string, string> UIfolders, ref Dictionary<string, string> Resfolders, ref Dictionary<string, string> Luafolders, ref string strUICommonDir)
    {
        UIfolders.Clear();
        foreach (var uifolder in AssetDatabase.GetSubFolders(strUIDirRoot))
        {
            //Debug.Log("----------absolute path uifolder:  " + uifolder);
            string strFolder = uifolder.Substring(strUIDirRoot.Length + 1).ToLower();
            if (!strFolder.Equals("Common", StringComparison.CurrentCultureIgnoreCase))
                UIfolders.Add(strFolder, uifolder);
            else
                strUICommonDir = uifolder;
        }

        Resfolders.Clear();
        foreach (var resfolder in AssetDatabase.GetSubFolders(strResRoot))
        {
            //Debug.Log("----------absolute path resfolder:  " + resfolder);
            string strFolder = resfolder.Substring(strResRoot.Length + 1).ToLower();
            Resfolders.Add(strFolder, resfolder);
        }

        Luafolders.Clear();
        foreach (var luafolder in AssetDatabase.GetSubFolders(strLuaFilesRoot))
        {
            //Debug.Log("----------absolute path luafolder:  " + luafolder);
            string strFolder = luafolder.Substring(strLuaFilesRoot.Length + 1).ToLower();
            Luafolders.Add(strFolder, luafolder);
        }
    }

    /// <summary>
    /// Clear All AssetBundle name
    /// </summary>
    public static void ClearAssetBundleName()
    {
        string[] allABs = AssetDatabase.GetAllAssetBundleNames();
        int length = allABs.Length;
        Debug.Log("Clean AB before total is:" + length);
                
        int index = 1;

        foreach (var abItem in allABs)
        {
            EditorUtility.DisplayProgressBar("RemoveAssetBundleName", abItem, index * 1f / length);
            AssetDatabase.RemoveAssetBundleName(abItem, true);
            index++;
        }

        EditorUtility.ClearProgressBar();
    }

    #region UI
    static void SetUIAssetName(string strAssetsPath)
    {
        string assetName = strAssetsPath.Replace(strUIDirRoot + "/", "");
        AssetImporter assetImporter = AssetImporter.GetAtPath(strAssetsPath);
        if (assetImporter== null)
        {
            return;
        }

        int index = assetName.IndexOf("/");

        string strTemp = assetName.Substring(index + 1);
        if(strTemp.StartsWith("texture", StringComparison.CurrentCultureIgnoreCase))
        {

        }
        else if (strTemp.StartsWith("fonts", StringComparison.CurrentCultureIgnoreCase))
        {
            assetName = assetName.Replace(Path.GetExtension(assetName), ".font");
        }
        else if (strTemp.StartsWith("grid", StringComparison.CurrentCultureIgnoreCase))
        {
            assetName = assetName.Replace(Path.GetExtension(assetName), ".grid");
        }
        else
        {
            assetName = assetName.Replace(Path.GetExtension(assetName), ".unity3d");
        }
        assetImporter.assetBundleName = assetName;
    }

    public static void BuildUIAsset(string strUICommonDir, string strOutputDir, string strTempOutDir, string strPlugin,string sourcePath, bool bForceBuild = false)
    {
        EditorCommon.ClearConsole();

        strOutputDir += "/ui";
        strTempOutDir += "/ui";

        List<FileInfo> lstFiles = new List<FileInfo>();
        List<string> lstFilters = new List<string>();
        lstFilters.Add(".meta");
        EditorCommon.GetAllFiles(strUICommonDir, ref lstFiles, lstFilters);
        EditorCommon.GetAllFiles(sourcePath, ref lstFiles, lstFilters);
        string strTemp = "";
        for (int i = 0; i < lstFiles.Count; i++)
        {
            //Debug.LogFormat("-------------->>lstFiles{0}:  {1}", i, lstFiles[i].FullName);
            strTemp = EditorCommon.ReplaceSlash(lstFiles[i].FullName);
            strTemp = strTemp.Replace(Application.dataPath, "Assets");
            SetUIAssetName(strTemp);
        }

        EditorSettings.spritePackerMode = SplitAlpha ? SpritePackerMode.BuildTimeOnly : SpritePackerMode.Disabled;
        Debug.Log("------->>Begin Build" + strTempOutDir);
        BuildAssetBundleOptions op = BuildAssetBundleOptions.ChunkBasedCompression;
        if (bForceBuild)
        {
            op |= BuildAssetBundleOptions.ForceRebuildAssetBundle;
            Utility.FileUtils.Instance().ClearDirectory(strTempOutDir);
            Utility.FileUtils.Instance().ClearDirectory(strOutputDir + "/" + strPlugin);
            if (strPlugin.Equals("hall", System.StringComparison.CurrentCultureIgnoreCase))
            {
                Utility.FileUtils.Instance().ClearDirectory(strOutputDir + "/common");
            }
        }
        EditorCommon.CheckOrCreateDirectory(strOutputDir);
        EditorCommon.CheckOrCreateDirectory(strTempOutDir);

        AssetBundleManifest manifest = BuildPipeline.BuildAssetBundles(strTempOutDir, op, EditorUserBuildSettings.activeBuildTarget);
        //lua file
        string path = Application.dataPath + "/LuaScripts/" + strPlugin + "/ResConfig/";
        WriteLuaConfig(strPlugin, manifest, path, strPlugin + "UI.lua", "ui");
        path = Application.dataPath + "/LuaScripts/" + strPlugin + "/UI/";
        WriteFileLuaDefine(strPlugin, manifest, path,"atlas");
        WriteFileLuaDefine(strPlugin, manifest, path, "grid");
        EditorCommon.CopyFile(strTempOutDir, strOutputDir, new List<string>() { ".meta", ".manifest" }, (str) =>
        {
            EditorUtility.DisplayProgressBar("Copy", str, 0.5f);
        });
        EditorUtility.ClearProgressBar();
        Debug.Log("打包完成");
    }

    static void WriteFileLuaDefine(string strPlugin, AssetBundleManifest manifest, string path,string strType)
    {
        strPlugin = System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(strPlugin);
        strType = System.Threading.Thread.CurrentThread.CurrentCulture.TextInfo.ToTitleCase(strType);
        string strtype = strType.ToLower();
        EditorCommon.CheckOrCreateDirectory(path);
        FileStream fs = File.Open(path + strType +".lua", FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite);
        fs.SetLength(0);
        StringWriter sw = new StringWriter();
        sw.WriteLine("-------------------------------------------------------------------");
        sw.WriteLine("--This file is automatically generated. Do not modify it manually--");
        sw.WriteLine("-------------------------------------------------------------------");
        sw.WriteLine("local " + strPlugin + strType + " = {");
        StringBuilder sb = new StringBuilder();
        foreach (var assetBundle in manifest.GetAllAssetBundles())
        {
            if (assetBundle.EndsWith("." + strtype, StringComparison.CurrentCultureIgnoreCase))
            {
                string strName = assetBundle.Replace("." + strtype, "");
                int index = strName.LastIndexOf("/");
                strName = strName.Substring(index + 1);
                sb.Append(string.Format("{0} = '{1}',", strName.ToUpperInvariant(), "ui/" + assetBundle));
                sw.WriteLine(sb);
                sb.Remove(0, sb.Length);
            }
        }

        sw.WriteLine("}");
        sw.WriteLine("return " + strPlugin + strType);

    }

    #endregion

    #region Res
    public static void BuildPackRes(string strOutputDir, string strTempOutDir, string strPlugin, string sourcePath, bool bForceBuild = false)
    {
        EditorCommon.ClearConsole();

        strOutputDir += "/res";
        strTempOutDir += "/res";

        List<FileInfo> lstFiles = new List<FileInfo>();
        List<string> lstFilters = new List<string>();
        lstFilters.Add(".meta");

        //sourcePath is strart with Assets    e.g.:"Assets/PackRes/test"
        EditorCommon.GetAllFiles(sourcePath, ref lstFiles, lstFilters);
        string strTemp = "";
        List<string> lstFilePath = new List<string>();
        for (int i = 0; i < lstFiles.Count; i++)
        {
            //FullName has "\\" , need to replace to "/"
            strTemp = EditorCommon.ReplaceSlash(lstFiles[i].FullName);
            strTemp = strTemp.Replace(Application.dataPath, "Assets");
            lstFilePath.Add(strTemp);
        }
        List<string> lstDependencies = GetDependencies(lstFilePath);
        foreach (var item in lstDependencies)
        {
            if (item.EndsWith(".fbx") || item.EndsWith(".FBX") || item.EndsWith(".shader"))
            {
                continue;
            }
            SetResName(item, strPlugin);
        }
        Debug.Log("--------->>Begin PackRes AssetBuild:" + strTempOutDir);

        BuildAssetBundleOptions op = BuildAssetBundleOptions.ChunkBasedCompression;
        if (bForceBuild)
        {
            op |= BuildAssetBundleOptions.ForceRebuildAssetBundle;
            Utility.FileUtils.Instance().ClearDirectory(strTempOutDir + "/" + strPlugin);
            Utility.FileUtils.Instance().ClearDirectory(strOutputDir + "/" + strPlugin);
        }
        EditorCommon.CheckOrCreateDirectory(strOutputDir);
        EditorCommon.CheckOrCreateDirectory(strTempOutDir);

        AssetBundleManifest manifest = BuildPipeline.BuildAssetBundles(strTempOutDir, op, EditorUserBuildSettings.activeBuildTarget);

        //Lua file
        string dirPath = Application.dataPath + "/LuaScripts/" + strPlugin + "/ResConfig/";
        WriteLuaConfig(strPlugin, manifest, dirPath, strPlugin + "res.lua", "res");

        EditorCommon.CopyFile(strTempOutDir, strOutputDir, new List<string>() { ".meta", ".manifest" }, (str) =>
        {
            //TODO  修改Utility CopyDirectory 回调传参
            EditorUtility.DisplayProgressBar("Copy", str, 0.5f);
        });
        Debug.Log("--------->>Build Success");
        EditorUtility.ClearProgressBar();
    }

    /// <summary>
    /// Set res assetbundle name
    /// </summary>
    /// <param name="assetPath"></param>
    /// <param name="strPlugin"></param>
    static void SetResName(string assetPath,string strPlugin)
    {
        AssetImporter assetImporter = AssetImporter.GetAtPath(assetPath);
        if (assetImporter == null)
        {
            return;
        }
        string assetName = assetPath;
        assetName = assetName.Replace(strResRoot + "/" + strPlugin, "");

        //Different suffixes are set according to different paths
        if (assetName.StartsWith("Effect", StringComparison.CurrentCultureIgnoreCase))
        {
            assetName = assetName.Replace(Path.GetExtension(assetName), ".fx");
        }
        else if (assetName.StartsWith("sound", StringComparison.CurrentCultureIgnoreCase))
        {
            assetName = assetName.Replace(Path.GetExtension(assetName), ".mp3");
        }
        else if (assetName.StartsWith("texture", StringComparison.CurrentCultureIgnoreCase))
        {
            assetName = assetName.Replace(Path.GetExtension(assetName), ".tex");
        }
        else if (assetName.StartsWith("obj", StringComparison.CurrentCultureIgnoreCase))
        {
            assetName = assetName.Replace(Path.GetExtension(assetName), ".obj");
        }
        else
        {
            assetName = assetName.Replace(Path.GetExtension(assetName), ".unity3d");
        }
        assetImporter.assetBundleName = assetName;
    }


    /// <summary>
    /// Function is return dependencied used in build res assetbundle // Prevent dependency resources from being in the resource directory.
    /// </summary>
    /// <param name="filePaths"></param>
    /// <returns></returns>
    static List<string> GetDependencies(List<string> filePaths)
    {
        List<string> lstFilesPath = new List<string>();
        for (int i = 0; i < filePaths.Count; i++)
        {
            string[] tempDependencies = AssetDatabase.GetDependencies(filePaths[i]);
            for (int k = 0; k < tempDependencies.Length; k++)
            {
                Debug.LogFormat("-------->>filePath:  {0}  ----  dependencies:  {1}", filePaths[i], tempDependencies[k]);
                string strChild = tempDependencies[i];
                if (!strChild.StartsWith(strResRoot))
                {
                    continue;
                }
                if (!lstFilesPath.Contains(strChild) && !strChild.EndsWith(".cs") && !strChild.EndsWith(".js"))
                {
                    if (EditorCommon.IsExists(Application.dataPath + strChild.Replace("Assets", "")))
                        lstFilesPath.Add(strChild);
                }
            }
        }
        return lstFilesPath;
    }

    #endregion

    #region Lua

    public static void BuildLuaFiles(string strOutputDir, string strTempOutDir, string strPlugin, string strPath)
    {
        strOutputDir += "/lua";
        strTempOutDir += "/lua";

        EditorCommon.CheckOrCreateDirectory(strOutputDir);
        EditorCommon.CheckOrCreateDirectory(strTempOutDir);
        Debug.Log("------>>Begin Build Lua Files");

        string tempPath = Application.dataPath + "/luatemp/luascripts";
        List<FileInfo> lstFiles = new List<FileInfo>();
        List<string> lstFilter = new List<string>();
        lstFilter.Add(".meta");

        EditorCommon.GetAllFiles(strPath, ref lstFiles, lstFilter);
        Utility.FileUtils.Instance().ClearDirectory(tempPath.Replace("/luascripts", ""), true);
        Utility.FileUtils.Instance().CreateDir(tempPath);
        for (int i = 0; i < lstFiles.Count; i++)
        {
            byte[] bytes = File.ReadAllBytes(lstFiles[i].FullName);
            string strFullPath = EditorCommon.ReplaceSlash(lstFiles[i].FullName);
            string strName = strFullPath.Replace(Application.dataPath + "/", "").Replace(".lua", ".txt").Replace("\\", "/").Replace("/", "_").ToLower();

            File.WriteAllBytes(tempPath + "/" + strName, bytes);
        }
        AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport);

        AssetImporter assetImporter = AssetImporter.GetAtPath("Assets/luatemp");
        assetImporter.assetBundleName = strPlugin + ".lua";

        BuildAssetBundleOptions op = BuildAssetBundleOptions.ChunkBasedCompression;
        op |= BuildAssetBundleOptions.ForceRebuildAssetBundle;
        Utility.FileUtils.Instance().ClearDirectory(strTempOutDir);

        BuildPipeline.BuildAssetBundles(strTempOutDir, op, EditorUserBuildSettings.activeBuildTarget);
        EditorCommon.CopyFile(strTempOutDir, strOutputDir, new List<string>() { ".meta", ".manifest" }, (str) =>
        {
            EditorUtility.DisplayProgressBar("Copy", str, 0.5f);
        });
        EditorUtility.ClearProgressBar();

        Utility.FileUtils.Instance().ClearDirectory(tempPath.Replace("/luascripts", ""), true);
        AssetDatabase.Refresh(ImportAssetOptions.ForceSynchronousImport);
    }


    #endregion

    static void WriteLuaConfig(string strPlugin, AssetBundleManifest manifest, string outDirPath, string strFileName, string strType)
    {
        EditorCommon.CheckOrCreateDirectory(outDirPath);
        FileStream fs = File.Open(outDirPath + strFileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite);
        fs.SetLength(0);
        StreamWriter sw = new StreamWriter(fs);
        sw.WriteLine("-------------------------------------------------------------------");
        sw.WriteLine("--This file is automatically generated. Do not modify it manually--");
        sw.WriteLine("-------------------------------------------------------------------");
        sw.WriteLine("local " + strPlugin + " = {");
        StringBuilder sb = new System.Text.StringBuilder();
        strType += "/";
        foreach (var assetBundle in manifest.GetAllAssetBundles())
        {
            if (assetBundle.StartsWith(strPlugin, StringComparison.CurrentCultureIgnoreCase))
            {
                string[] strDependencies = manifest.GetAllDependencies(assetBundle);
                if (strDependencies == null || strDependencies.Length == 0)
                {
                    continue;
                }
                sb.Append("{[\"Name\"]=\"" + strType + assetBundle + "\",[\"Dependencies\"]={");
                foreach (var dependence in strDependencies)
                {
                    sb.Append("\"" + strPlugin + dependence + "\",");
                }
                sb.Remove(sb.Length - 1,1);
                sb.Append("}},");
                sw.WriteLine(sb);
                sb.Remove(0, sb.Length);
            }
        }
        sw.WriteLine("}");
        sw.WriteLine("return " + strPlugin);

        sw.Close();
        fs.Close();
    }


}
